package folder.main.exp0.controllers.linearProgramming;

import java.util.LinkedHashMap;

import cern.colt.list.tint.IntArrayList;

import com.jom.DoubleMatrixND;
import com.jom.OptimizationProblem;

import folder.main.exp0.controllers.ControllerFinding;
import folder.model.network.Network;
import folder.model.node.Node;

public abstract class LinearProgramming extends ControllerFinding
{
	protected Network network;
	protected double delays[][];
	protected int T;
	
	public LinearProgramming( Network network, double delays[][], int T )
	{
		this.network = network;
		this.delays = delays;
		this.T = T;
	}
	
	protected OptimizationProblem optimizationProblem( double costABW[] ){ return null; }
	
	protected DoubleMatrixND arranging( OptimizationProblem op )
	{	
		for( int i = 0; i < delays.length; i++ )
		{
			String string = new String();
			boolean control = false;
			
			for( int j = 0; j < delays.length; j++ )
				if( 0 < delays[i][j] && delays[i][j] <= T )
					if( control == false )
					{
						string += "c(" + j + ")";
						control = true;
					}
					else
						string += " + c(" + j + ")";
			
			if( !string.equals( "" ) )
				op.addConstraint( string + " >= 1" );
			else
				throw new RuntimeException( "Not below T" );
		}
		
	  	op.solve( "glpk" );

		if( !op.solutionIsOptimal() )
			throw new RuntimeException( "An optimal solution was not found" );
		
		DoubleMatrixND c  = op.getPrimalSolution( "c" );
		
		IntArrayList indexList = new IntArrayList();
		c.getPositiveValues( indexList, null );
		//System.out.println( "Controllers: " + indexList.size() + " " + indexList );
		//System.out.println( "Optimal cost: " + op.getOptimalCost() );
		
		return c;
	}
	
	protected LinkedHashMap< Node, Node > matching( DoubleMatrixND c )
	{
		OptimizationProblem op = new OptimizationProblem();
		op.setInputParameter( "d", delays );
		op.addDecisionVariable( "n", true, new int[]{ delays.length, delays.length }, 0, 1);
		op.setObjectiveFunction( "minimize", "sum( d .* n )" );
		
		for( int i = 0; i < delays.length; i++ )
			if( c.get( i ) == 1 )
			{
				op.addConstraint( "sum( n( " + i + ", all ) ) >= 1" );
				op.addConstraint( "sum( n( all, " + i + " ) ) == 0" );
			}
			else
			{
				op.addConstraint( "sum( n( " + i + ", all ) ) == 0" );
				op.addConstraint( "sum( n( all, " + i + " ) ) == 1" );
			}
		
		op.addConstraint( "sum( d .* n ) >= 1" );
		
		IntArrayList indexList = new IntArrayList();
		c.getNonZeros( indexList, null );
		op.addConstraint( "sum(n) == " + ( delays.length - indexList.size() ) );
		
		op.solve( "glpk" );

		if( !op.solutionIsOptimal () )
			throw new RuntimeException( "An optimal solution was not found" );
		
		DoubleMatrixND n = op.getPrimalSolution( "n" );
		op.setInputParameter( "n", n );
		//System.out.println( "n: " + n );
		
		LinkedHashMap< Node, Node > matches = new LinkedHashMap< Node, Node >();
		//int k = 0;
		
		for( int i = 0; i < delays.length; i++ )
			for( int j = 0; j < delays.length; j++ )
				if( op.parseExpression( "n( " + i + "," + j + " )" ).evaluate().toValue() == 1 )
				{
					matches.put( network.getNode( j ), network.getNode( i ));
					//System.out.println( "match(" + i + "," + j + "): " + optimizationProblem.parseExpression( "d(" + i + "," + j + ")" ).evaluate().toValue() );
					//k++;
				}
		
		return matches;
		//System.out.println( "Number of matches: " + k );
		//System.out.println( "Total delay: " + optimizationProblem.getOptimalCost() );
	}
	
}
